package com.wmh.baseservice.operationaid.utils;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.operationaid.entity.TbStoreData;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author 谢骏
 * @date 2023/7/28 16:21
 * 计算相关工具类
 **/
public class CalculateUtils {

    /**
     * 计算对象数值字段差值百分比以及差值
     *
     * @param <T>   对比数据的类对象类型
     * @param <R>   计算结果类对象类型
     * @param o1    左侧对象,即 数据日期较小的数值对象
     * @param o2    右侧对象,即 数据日期较大的数值对象
     * @param rType 返回类对象
     * @return 返回类对象列表 下标0 为差值 下标1 为百分比
     */
    public static <T, R> List<R> calObjectNumberFieldDiffPer(T o1, T o2, Class<R> rType) {
        ArrayList<R> rList = new ArrayList<>();
        try {
            R r1 = rType.getConstructor().newInstance();
            R r2 = rType.getConstructor().newInstance();
            // 反射获取字段列表
            Class<?> clazz = o1.getClass();
            Field[] fields = ReflectUtil.getFields(clazz);
            for (Field f : fields) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                f.setAccessible(true);
                Object v1 = f.get(o1);
                Object v2 = f.get(o2);
                if (isAllNumber(v1, v2)) {
                    BigDecimal[] diff = calculateDiff(v1, v2);
                    ReflectUtil.setFieldValue(r1, f.getName(), diff[0]);
                    ReflectUtil.setFieldValue(r2, f.getName(), diff[1]);
                }
            }
            rList.add(r1);
            rList.add(r2);
        } catch (Exception e) {
            throw new ServiceException("计算差值百分比时失败 : " + e.getMessage());
        }
        return rList;
    }


    private static boolean isAllNumber(Object... o) {
        return Arrays.stream(o).allMatch(Number.class::isInstance);
    }

    /**
     * 计算两个值的差值 以及相差的百分比
     *
     * @return 一个 BigDecimal 数组第一个元素时差值 第二个元素是百分比
     */
    public static BigDecimal[] calculateDiff(Object v1, Object v2) {
        if (v1 == null || v2 == null) {
            return new BigDecimal[]{null, null};
        }
        BigDecimal b1 = new BigDecimal(v1.toString());
        BigDecimal b2 = new BigDecimal(v2.toString());
        BigDecimal difference = (b1.subtract(b2));
        BigDecimal scale;
        if (b2.compareTo(BigDecimal.ZERO) != 0) {
            scale = difference.divide(b2, 4, RoundingMode.HALF_UP);
        } else {
            scale = difference;
        }
        return new BigDecimal[]{difference.setScale(2, RoundingMode.HALF_UP), scale.multiply(new BigDecimal("100.00")).setScale(2, RoundingMode.HALF_UP)};
    }

    public static Object sumTwoValue(Field field, TbStoreData t1, TbStoreData t2) throws IllegalAccessException {
        field.setAccessible(true);
        if (!Number.class.isAssignableFrom(field.getType())) {
            throw new ServiceException("非数字字段");
        }
        Object v1 = field.get(t1);
        Object v2 = field.get(t2);
        if (field.getType().equals(BigDecimal.class)) {
            return NumberUtil.add(v1 == null ? BigDecimal.ZERO : (BigDecimal) v1,
                    v2 == null ? BigDecimal.ZERO : (BigDecimal) v2);
        } else if (field.getType().equals(Long.class)) {
            return Long.sum(v1 == null ? 0L : (Long) v1 ,v2 == null ? 0L : (Long) v2);
        } else if (field.getType().equals(Integer.class)){
            return Integer.sum(v1 == null ? 0 : (Integer) v1 ,v2 == null ? 0 : (Integer) v2);
        }
        throw new ServiceException("请补充数值类型 : " + field.getType());
    }


    @AllArgsConstructor
    @Data
    public static class Item {
        private String v1;
        private int v2;
        private Integer v3;
        private BigDecimal v4;
        private double v5;
    }

    @Data
    public static class R {
        private BigDecimal v1;
        private BigDecimal v2;
        private BigDecimal v3;
        private BigDecimal v4;
        private BigDecimal v5;
    }

    public static void main(String[] args) {
        Item item1 = new Item("123", 100, 120, new BigDecimal("10.5"), 50.5);
        Item item2 = new Item("456", 110, 10, new BigDecimal("0.5"), 200);
        System.out.println(calObjectNumberFieldDiffPer(item1, item2, R.class));
    }
}
